package cn.com.simple.learning.webflux.handler;

import cn.com.simple.learning.core.entity.User;
import cn.com.simple.learning.webflux.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.annotation.NonNull;

import java.util.ArrayList;
import java.util.concurrent.CompletableFuture;

/**
 * @author Jianxing.Jia
 * @date 2022/6/7
 * @description 描述信息
 */
@Component
public class UserHandler {

    private static final Logger logger = LoggerFactory.getLogger(UserHandler.class);

    private final UserService userService;

    public UserHandler(UserService userService) {
        this.userService = userService;
    }

    public Mono<ServerResponse> hello(ServerRequest serverRequest) {
        return ServerResponse.ok().body(Mono.just("hello"), String.class);
    }

    /**
     * 根据id获取用户数据
     * @param serverRequest
     * @return
     */
    public Mono<ServerResponse> getUserById(ServerRequest serverRequest) {
        String id = serverRequest.pathVariable("id");
        long startTime = System.currentTimeMillis();
        logger.info("开始执行根据id查询用户，startTime：{}", startTime);

        Mono<ServerResponse> result = ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
                .body(Mono.fromCompletionStage(CompletableFuture.supplyAsync(() -> this.userService.getById(id))), User.class);
        long endTime = System.currentTimeMillis();
        long costTime = endTime - startTime;
        logger.info("执行根据id查询用户结束，endTime：{}", endTime);
        logger.info("花费时间，costTime：{} 毫秒", costTime);
        return result;
    }

    public Mono<ServerResponse> getUserByIdSync(ServerRequest serverRequest) {
        String id = serverRequest.pathVariable("id");
        long startTime = System.currentTimeMillis();
        logger.info("sync 开始执行根据id查询用户，startTime：{}", startTime);

        Mono<ServerResponse> result = ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
                .body(Mono.fromSupplier(() -> this.userService.getById(id)), User.class);
        long endTime = System.currentTimeMillis();
        long costTime = endTime - startTime;
        logger.info("sync 执行根据id查询用户结束，endTime：{}", endTime);
        logger.info("sync 花费时间，costTime：{} 毫秒", costTime);
        return result;
    }

    /**
     * 根据id删除用户，返回值是boolean
     * @param serverRequest
     * @return
     */
    public Mono<ServerResponse> deleteUserById(ServerRequest serverRequest) {
        String id = serverRequest.pathVariable("id");
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
                .body(Mono.just(this.userService.removeById(id)), Boolean.class)
                .switchIfEmpty(ServerResponse.notFound().build());
    }

    /**
     * 保存用户信息
     * @param serverRequest
     * @return
     */
    public Mono<ServerResponse> save(ServerRequest serverRequest) {
        Mono<User> userMono = serverRequest.bodyToMono(User.class);
        return userMono.flatMap(userDTO ->
                ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
                        .body(Mono.create(u -> u.success(this.userService.save(userDTO))), Boolean.class));
    }

    /**
     * 获取所有用户数据 数组形式 一次性获取
     * @param serverRequest
     * @return
     */
    public Mono<ServerResponse> getUsers(@NonNull ServerRequest serverRequest) {
        return ServerResponse.ok().body(Mono.just(this.userService.list()), User.class);
    }

    /**
     * 获取所有用户数据 流形式 一条条获取
     * @param serverRequest
     * @return
     */
    public Mono<ServerResponse> getUsersByStream(ServerRequest serverRequest) {
        return ServerResponse.ok().contentType(MediaType.TEXT_EVENT_STREAM)
                .body(Mono.just(this.userService.list()), User.class)
                .switchIfEmpty(ServerResponse.ok().body(new ArrayList<>(), User.class));
    }

}
